{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "0",
   "metadata": {},
   "source": [
    "# Shapes and generic cells\n",
    "\n",
    "gdsfactory provides some generic parametric cells in `gf.components` that you can customize for your application."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1",
   "metadata": {},
   "source": [
    "## Basic shapes"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2",
   "metadata": {},
   "source": [
    "### Rectangle\n",
    "\n",
    "To create a simple rectangle, there are two functions:\n",
    "\n",
    "``gf.components.rectangle()`` can create a basic rectangle:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3",
   "metadata": {},
   "outputs": [],
   "source": [
    "import gdsfactory as gf\n",
    "\n",
    "r1 = gf.components.rectangle(size=(4.5, 2), layer=(1, 0))\n",
    "r1.plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4",
   "metadata": {},
   "source": [
    "``gf.components.bbox()`` can also create a rectangle based on a bounding box.\n",
    "This is useful if you want to create a rectangle which precisely surrounds a piece of existing geometry.\n",
    "For example, if we have an arc geometry and we want to define a box around it, we can use ``gf.components.bbox()``:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5",
   "metadata": {},
   "outputs": [],
   "source": [
    "c = gf.Component()\n",
    "arc = c << gf.components.bend_circular(radius=10, width=0.5, angle=90, layer=(1, 0))\n",
    "arc.rotate(90)\n",
    "\n",
    "# Draw a rectangle around the arc we created by using the arc's bounding box.\n",
    "rect = c << gf.components.bbox(arc, layer=(2, 0))\n",
    "c.plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6",
   "metadata": {},
   "source": [
    "### Cross\n",
    "\n",
    "The ``gf.components.cross()`` function creates a cross structure:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7",
   "metadata": {},
   "outputs": [],
   "source": [
    "c = gf.components.cross(length=10, width=0.5, layer=(1, 0))\n",
    "c.plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8",
   "metadata": {},
   "source": [
    "### Ellipse\n",
    "\n",
    "The ``gf.components.ellipse()`` function creates an ellipse by defining the major and minor radii:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9",
   "metadata": {},
   "outputs": [],
   "source": [
    "c = gf.components.ellipse(radii=(10, 5), angle_resolution=2.5, layer=(1, 0))\n",
    "c.plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "10",
   "metadata": {},
   "source": [
    "### Circle\n",
    "\n",
    "The ``gf.components.circle()`` function creates a circle:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "11",
   "metadata": {},
   "outputs": [],
   "source": [
    "c = gf.components.circle(radius=10, angle_resolution=2.5, layer=(1, 0))\n",
    "c.plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "12",
   "metadata": {},
   "source": [
    "### Ring\n",
    "\n",
    "The ``gf.components.ring()`` function creates a ring.  The radius refers to the center radius of the ring structure (halfway between the inner and outer radius)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "13",
   "metadata": {},
   "outputs": [],
   "source": [
    "c = gf.components.ring(radius=5, width=0.5, angle_resolution=2.5, layer=(1, 0))\n",
    "c.plot()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "14",
   "metadata": {},
   "outputs": [],
   "source": [
    "c = gf.components.ring_single(gap=0.2, radius=10, length_x=4, length_y=2)\n",
    "c.plot()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "15",
   "metadata": {},
   "outputs": [],
   "source": [
    "import gdsfactory as gf\n",
    "\n",
    "c = gf.components.ring_double(gap=0.2, radius=10, length_x=4, length_y=2)\n",
    "c.plot()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "16",
   "metadata": {},
   "outputs": [],
   "source": [
    "c = gf.components.ring_double(\n",
    "    gap=0.2,\n",
    "    radius=10,\n",
    "    length_x=4,\n",
    "    length_y=2,\n",
    "    bend=gf.components.bend_circular,\n",
    ")\n",
    "c.plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "17",
   "metadata": {},
   "source": [
    "### Bend circular\n",
    "\n",
    "The ``gf.components.bend_circular()`` function creates an arc.  The radius refers to the center radius of the arc (halfway between the inner and outer radius)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "18",
   "metadata": {},
   "outputs": [],
   "source": [
    "c = gf.components.bend_circular(\n",
    "    radius=5.0, width=0.5, angle=90, npoints=720, layer=(1, 0)\n",
    ")\n",
    "c.plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "19",
   "metadata": {},
   "source": [
    "### Bend euler\n",
    "\n",
    "The ``gf.components.bend_euler()`` function creates an adiabatic bend in which the bend radius changes gradually. Euler bends have lower loss than circular bends.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "20",
   "metadata": {},
   "outputs": [],
   "source": [
    "c = gf.components.bend_euler(radius=5.0, width=0.5, angle=90, npoints=720, layer=(1, 0))\n",
    "c.plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "21",
   "metadata": {},
   "source": [
    "### Tapers\n",
    "\n",
    "`gf.components.taper()`is defined by setting its length as well as its start and end length.  It has two ports, ``1`` and ``2``, on either end, allowing you to easily connect it to other structures."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "22",
   "metadata": {},
   "outputs": [],
   "source": [
    "c = gf.components.taper(length=10, width1=6, width2=4, port=None, layer=(1, 0))\n",
    "c.plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "23",
   "metadata": {},
   "source": [
    "`gf.components.ramp()` is a structure is similar to `taper()` except it is asymmetric.  It also has two ports, ``1`` and ``2``, on either end."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "24",
   "metadata": {},
   "outputs": [],
   "source": [
    "c = gf.components.ramp(length=10, width1=4, width2=8, layer=(1, 0))\n",
    "c.plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "25",
   "metadata": {},
   "source": [
    "### Common compound shapes"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "26",
   "metadata": {},
   "source": [
    "The `gf.components.L()` function creates a \"L\" shape with ports on either end named ``1`` and ``2``."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "27",
   "metadata": {},
   "outputs": [],
   "source": [
    "c = gf.components.L(width=7, size=(10, 20), layer=(1, 0))\n",
    "c.plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "28",
   "metadata": {},
   "source": [
    "The `gf.components.C()` function creates a \"C\" shape with ports on either end named ``1`` and ``2``."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "29",
   "metadata": {},
   "outputs": [],
   "source": [
    "c = gf.components.C(width=7, size=(10, 20), layer=(1, 0))\n",
    "c.plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "30",
   "metadata": {},
   "source": [
    "## Text\n",
    "\n",
    "Gdsfactory has an implementation of the DEPLOF font with the majority of english ASCII characters represented (thanks to PHIDL)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "31",
   "metadata": {},
   "outputs": [],
   "source": [
    "c = gf.components.text(\n",
    "    text=\"Hello world!\\nMultiline text\\nLeft-justified\",\n",
    "    size=10,\n",
    "    justify=\"left\",\n",
    "    layer=(1, 0),\n",
    ")\n",
    "c.plot()\n",
    "# The justify parameter needs to be 'left', 'center', or 'right',\n",
    "# because those are the standard text alignment options that determine how multiple lines of text are positioned relative to each other."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "32",
   "metadata": {},
   "source": [
    "## Lithography Structures\n",
    "\n",
    "### Step-resolution\n",
    "\n",
    "The `gf.components.litho_steps()` function creates a lithographic test structure that is useful for measuring the resolution of photoresist or electron-beam resists.  It provides both positive-tone and negative-tone resolution tests."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "33",
   "metadata": {},
   "outputs": [],
   "source": [
    "c = gf.components.litho_steps(\n",
    "    line_widths=(1, 2, 4, 8, 16), line_spacing=10, height=100, layer=(1, 0)\n",
    ")\n",
    "c.plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "34",
   "metadata": {},
   "source": [
    "### Calipers (inter-layer alignment)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "35",
   "metadata": {},
   "source": [
    "The `gf.components.litho_calipers()` function is used to detect offsets in multilayer fabrications.  It creates a set of two notches on different layers.  When a fabrication error/offset occurs, it is easy to detect the magnitude of the offset because both center-notches are no longer aligned."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "36",
   "metadata": {},
   "outputs": [],
   "source": [
    "D = gf.components.litho_calipers(\n",
    "    notch_size=(1, 5),\n",
    "    notch_spacing=2,\n",
    "    num_notches=7,\n",
    "    offset_per_notch=0.1,\n",
    "    row_spacing=0,\n",
    "    layer1=(1, 0),\n",
    "    layer2=(2, 0),\n",
    ")\n",
    "D.plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "37",
   "metadata": {},
   "source": [
    "## Paths\n",
    "\n",
    "See **Path tutorial** for more details -- this is just an enumeration of the available built-in Path functions"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "38",
   "metadata": {},
   "source": [
    "### Circular arc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "39",
   "metadata": {},
   "outputs": [],
   "source": [
    "P = gf.path.arc(radius=10, angle=135, npoints=720)\n",
    "f = P.plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "40",
   "metadata": {},
   "source": [
    "### Straight"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "41",
   "metadata": {},
   "outputs": [],
   "source": [
    "import gdsfactory as gf\n",
    "\n",
    "P = gf.path.straight(length=5, npoints=100)\n",
    "f = P.plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "42",
   "metadata": {},
   "source": [
    "### Euler curve\n",
    "\n",
    "Also known as a straight-to-bend, clothoid, racetrack, or track transition, this path tapers adiabatically from straight to curved. Often used to minimize losses in photonic straights.  If `p < 1.0`, it will create a \"partial euler\" curve as described in Vogelbacher et. al. https://dx.doi.org/10.1364/oe.27.031394.  \n",
    "If the `use_eff` argument is false, `radius` corresponds to minimum radius of curvature of the bend.  If `use_eff`  is true, `radius` corresponds to the \"effective\" radius of the bend-- The curve will be scaled such that the endpoints match an arc with parameters `radius` and `angle`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "43",
   "metadata": {},
   "outputs": [],
   "source": [
    "P = gf.path.euler(radius=3, angle=90, p=1.0, use_eff=False, npoints=720)\n",
    "f = P.plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "44",
   "metadata": {},
   "source": [
    "### Smooth path from waypoints"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "45",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "import gdsfactory as gf\n",
    "\n",
    "points = np.array([(20, 10), (40, 10), (20, 40), (50, 40), (50, 20), (70, 20)])\n",
    "\n",
    "P = gf.path.smooth(\n",
    "    points=points,\n",
    "    radius=2,\n",
    "    bend=gf.path.euler,\n",
    "    use_eff=False,\n",
    ")\n",
    "f = P.plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "46",
   "metadata": {},
   "source": [
    "### Delay spiral\n",
    "\n",
    "A delay spiral is a long optical waveguide coiled into a spiral shape on a photonic integrated circuit. Its purpose is to create a significant time delay for an optical signal within a very compact area."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "47",
   "metadata": {},
   "outputs": [],
   "source": [
    "c = gf.components.spiral_double()\n",
    "c.plot()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "48",
   "metadata": {},
   "outputs": [],
   "source": [
    "c = gf.components.spiral()\n",
    "c.plot()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "49",
   "metadata": {},
   "outputs": [],
   "source": [
    "c = gf.components.spiral_racetrack_fixed_length()\n",
    "c.plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "50",
   "metadata": {},
   "source": [
    "## Useful contact pads / connectors\n",
    "\n",
    "These functions are common shapes with ports, often used to make contact pads."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "51",
   "metadata": {},
   "outputs": [],
   "source": [
    "c = gf.components.compass(size=(4, 2), layer=(1, 0))\n",
    "c.plot()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "52",
   "metadata": {},
   "outputs": [],
   "source": [
    "c = gf.components.nxn(north=3, south=4, east=0, west=0)\n",
    "c.plot()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "53",
   "metadata": {},
   "outputs": [],
   "source": [
    "c = gf.components.pad()\n",
    "c.plot()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "54",
   "metadata": {},
   "outputs": [],
   "source": [
    "c = gf.components.pad_array90(columns=3)\n",
    "c.plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "55",
   "metadata": {},
   "source": [
    "## Chip / die template"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "56",
   "metadata": {},
   "outputs": [],
   "source": [
    "import gdsfactory as gf\n",
    "\n",
    "c = gf.components.die(\n",
    "    size=(10000, 5000),  # Size of the die.\n",
    "    street_width=100,  # Width of corner marks for die-sawing.\n",
    "    street_length=1000,  # Length of corner marks for die-sawing.\n",
    "    die_name=\"chip99\",  # Label text.\n",
    "    text_size=500,  # Label text size.\n",
    "    text_location=\"SW\",  # Label text compass location e.g. 'S', 'SE', 'SW'\n",
    "    layer=(2, 0),\n",
    "    bbox_layer=(3, 0),\n",
    ")\n",
    "c.plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "57",
   "metadata": {},
   "source": [
    "## Optimal superconducting curves\n",
    "\n",
    "The following structures are meant to reduce \"current crowding\" in superconducting thin-film structures (such as superconducting nanowires).\n",
    "They are the result of conformal mapping equations derived in  Clem, J. & Berggren, K. \"[Geometry-dependent critical currents in superconducting nanocircuits.\" Phys. Rev. B 84, 1–27 (2011).](http://dx.doi.org/10.1103/PhysRevB.84.174510)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "58",
   "metadata": {},
   "outputs": [],
   "source": [
    "import gdsfactory as gf\n",
    "\n",
    "# This code creates a compact, U-shaped \"hairpin\" delay line with bends that are optimized for low loss.\n",
    "c = gf.components.optimal_hairpin(\n",
    "    width=0.2, pitch=0.6, length=10, turn_ratio=4, num_pts=50, layer=(2, 0)\n",
    ")\n",
    "c.plot()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "59",
   "metadata": {},
   "outputs": [],
   "source": [
    "# This code creates a taper, which is a waveguide section that smoothly transitions between two different widths.\n",
    "# The optimal_step component is special because its shape is mathematically optimized to be adiabatic, minimizing light loss and back-reflections.\n",
    "c = gf.components.optimal_step(\n",
    "    start_width=10, # Defines the initial width of the taper.\n",
    "    end_width=22, # Defines the final width of the taper.\n",
    "\n",
    "    # num_pts=50: This sets the number of points used to define the optimized S-curve. A higher number results in a smoother, more finely detailed curve.\n",
    "    num_pts=50,\n",
    "\n",
    "    # This is the width tolerance. It defines how close the optimization algorithm must get to the target end_width.\n",
    "    # A smaller value results in a more precise, but potentially longer, taper.\n",
    "    width_tol=1e-3,\n",
    "\n",
    "    # This factor adjusts the \"aggressiveness\" of the S-curve.\n",
    "    # A larger value creates a more gradual, less crowded transition at the start and end of the taper.\n",
    "    anticrowding_factor=1.2,\n",
    "\n",
    "    # This parameter creates a one-sided taper. One edge of the taper will be a straight line, while the other will have the optimized S-curve.\n",
    "    # If True, both sides would curve symmetrically.\n",
    "    symmetric=False,\n",
    "    layer=(2, 0),\n",
    ")\n",
    "c.plot()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "60",
   "metadata": {},
   "outputs": [],
   "source": [
    "c = gf.components.optimal_90deg(width=100.0, num_pts=15, length_adjust=1, layer=(2, 0))\n",
    "c.plot()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "61",
   "metadata": {},
   "outputs": [],
   "source": [
    "# This code creates a Superconducting Nanowire Single-Photon Detector (SNSPD), a specialized component designed to detect single photons of light.\n",
    "c = gf.components.snspd(\n",
    "    wire_width=0.2,\n",
    "    wire_pitch=0.6,\n",
    "    size=(10, 8), # The overall dimensions of the meandered detector area are 10x8 µm.\n",
    "    num_squares=None, # num_squares=None means that the size of the component is being defined by the size parameter.\n",
    "    turn_ratio=4, # Controls the shape of the 180-degree bends in the meander(Clojure/Clojurescript library).\n",
    "    terminals_same_side=False, # The input and output terminals will be on opposite sides of the detector.\n",
    "    layer=(2, 0),\n",
    ")\n",
    "c.plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "62",
   "metadata": {},
   "source": [
    "## Generic library\n",
    "\n",
    "gdsfactory comes with a [generic library](https://gdsfactory.github.io/gdsfactory/components.html) that you can customize to your needs or even modify the internal code to create the components that you need."
   ]
  }
 ],
 "metadata": {
  "jupytext": {
   "cell_metadata_filter": "-all",
   "main_language": "python",
   "notebook_metadata_filter": "-all"
  },
  "kernelspec": {
   "display_name": "base",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
